package com.taobao.api.internal.tmc;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import com.taobao.top.link.LinkException;
import com.taobao.top.link.Logger;
import com.taobao.top.link.LoggerFactory;
import com.taobao.top.link.channel.ChannelException;
import com.taobao.top.link.channel.ClientChannelSharedSelector;
import com.taobao.top.link.channel.embedded.EmbeddedClientChannelSharedSelector;
import com.taobao.top.link.endpoint.Endpoint;
import com.taobao.top.link.endpoint.EndpointChannelHandler;
import com.taobao.top.link.endpoint.EndpointProxy;
import com.taobao.top.link.endpoint.Identity;
import com.taobao.top.link.endpoint.MessageHandler;
import com.taobao.top.link.logging.LogUtil;

// poll-push mix client
class MixClient {

  protected Logger      logger;
  protected Identity    id;
  private Endpoint      endpoint;
  private URI           serverUri;
  private EndpointProxy server;

  private Timer         timer;
  protected int         reconnectInterval = 30000;

  public MixClient(Identity id) {
    // whatever, log first
    LoggerFactory loggerFactory = LogUtil.getLoggerFactory(this);
    this.logger = loggerFactory.create(this);

    // sharedpool with heartbeat 60s
    // ClientChannelSharedSelector selector = new
    // ClientChannelSharedSelector(loggerFactory);
    ClientChannelSharedSelector selector = new EmbeddedClientChannelSharedSelector(loggerFactory);
    selector.setHeartbeat(60000);

    // custom scheduler
    EndpointChannelHandler channelHandler = new EndpointChannelHandler(loggerFactory);
    // client do not need complex scheduler
    // channelHandler.setScheduler(scheduler);

    this.endpoint = new Endpoint(loggerFactory, this.id = id);
    this.endpoint.setClientChannelSelector(selector);
    this.endpoint.setChannelHandler(channelHandler);
  }

  public void setMessageHandler(MessageHandler handler) {
    this.endpoint.setMessageHandler(handler);
  }

  public final void connect(String uri) throws LinkException {
    try {
      this.connect(new URI(uri));
    } catch (URISyntaxException e) {
      this.logger.error(e);
    }
  }

  public final void connect(URI uri) throws LinkException {
    this.server = this.endpoint.getEndpoint(new ServerIdentity(), uri, this.createConnectHeaders());
    this.serverUri = uri;
    this.doReconnect();
    this.logger.info("connected to tmc server: %s", this.serverUri);
  }

  public void disconnect() {
  }

  public final void send(Map<String, String> message) throws ChannelException {
    this.server.send(message);
  }

  public final void sendAndWait(Map<String, String> message, int timeout) throws LinkException {
    this.server.sendAndWait(message, timeout);
  }

  protected Map<String, String> createConnectHeaders() {
    return null;
  }

  private void doReconnect() {
    this.stopReconnect();
    this.timer = new Timer();
    this.timer.schedule(new TimerTask() {
      @Override
      public void run() {
        try {
          if (server.hasValidSender())
            return;
        } catch (Exception e) {
          logger.warn(e);
        }
        try {
          logger.warn("reconnecting...");
          connect(serverUri);
        } catch (LinkException e) {
          logger.warn("reconnect error", e);
        }
      }
    }, this.reconnectInterval, this.reconnectInterval);
  }

  private void stopReconnect() {
    if (this.timer == null)
      return;
    this.timer.cancel();
  }

  public class ServerIdentity implements Identity {
    public Identity parse(Object data) throws LinkException {
      return null;
    }

    public void render(Object to) {
    }

    public boolean equals(Identity id) {
      return id instanceof ServerIdentity;
    }

    public String toString() {
      return id.toString();
    }
  }
}
